package com.xyzwps.orm.ktorm.repository

import com.xyzwps.orm.exception.TagDuplicateException
import com.xyzwps.orm.model.Tag
import com.xyzwps.orm.repository.TagRepository
import com.xyzwps.orm.util.ExceptionUtils
import me.liuwj.ktorm.database.Database
import me.liuwj.ktorm.dsl.eq
import me.liuwj.ktorm.entity.add
import me.liuwj.ktorm.entity.filter
import me.liuwj.ktorm.entity.find
import me.liuwj.ktorm.entity.map
import java.lang.IllegalStateException
import java.sql.SQLIntegrityConstraintViolationException
import java.util.*

class KtormTagRepository(private val db: Database) : TagRepository {

    override fun insert(tag: Tag): Int {
        try {
            val tagEntity = TagEntity {
                tagName = tag.tagName
                userId = tag.userId
            }
            db.tags.add(tagEntity)
            return tagEntity.tagId
        } catch (ex: Exception) {
            if (ExceptionUtils.causedBy(ex, SQLIntegrityConstraintViolationException::class.java)) {
                throw TagDuplicateException(tag.tagName)
            } else {
                throw IllegalStateException(ex)
            }
        }
    }

    override fun update(tag: Tag) {
        try {
            val tagEntity = db.tags.find { it.tagId eq tag.tagId } ?: return
            tagEntity.tagName = tag.tagName
            tagEntity.userId = tag.userId
            tagEntity.flushChanges()
        } catch (ex: Exception) {
            if (ExceptionUtils.causedBy(ex, SQLIntegrityConstraintViolationException::class.java)) {
                throw TagDuplicateException(tag.tagName)
            } else {
                throw IllegalStateException(ex)
            }
        }
    }

    override fun delete(tagId: Int) {
        val tagEntity = db.tags.find { it.tagId eq tagId } ?: return
        tagEntity.delete()
    }

    override fun selectByTagId(tagId: Int): Optional<Tag> {
        val tagEntity = db.tags.find { it.tagId eq tagId }
        return Optional.ofNullable(tagEntity?.toTag())
    }

    override fun selectAllForUser(userId: Int): List<Tag> {
        // TODO: 有意思，有点像集合操作了
        val tagEntities = db.tags.filter { it.userId eq userId }
        return tagEntities.map { it.toTag() }
    }
}